package com.qf.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import com.qf.feign.OrderFeignClient;
import com.qf.pojo.Order;
import com.qf.pojo.Result;
import com.qf.pojo.User;
import com.qf.server.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.List;
import java.util.Random;

@RestController
@RequestMapping("/user")
@RefreshScope //当配置发生变化后，这个注解标注的类对象会重建
public class UserController {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private DiscoveryClient discoveryClient;

    @Autowired
    private LoadBalancerClient loadBalancerClient;

    @Autowired
    private OrderFeignClient orderFeignClient;

    @Value("${desc}")
    private String desc;

    /*
        一个兜底方法：
            如果没有设置blockHandler，所有的异常都走这个方法
            如果设置了blockHandler，除了sentinel导致的异常外的其他异常都走这个方法

        在这个方法中，如果需要收集异常，可以在方法的参数列表最后使用Throwable作为方法参数，接收异常对象
        如果不需要异常信息，可以不用Throwable作为方法参数，接收异常对象
     */
    public Result findById_fb(Integer id,Throwable t){
        return Result.error("降级了~~");
    }

    /*
        FlowException : 流控异常
        DegradeException ： 降级异常
        ParamFlowException： 参数流控异常（热点）
        SystemBlockException： 系统流控异常

        所以只要是sentinel的流控导致的限制异常，都会触发blockHandler对应的方法
     */
    public Result findById_bh(Integer id, BlockException b){
//        if(b instanceof FlowException){
//
//        }else if (b instanceof DegradeException){
//
//        }
        return Result.error("block handler 降级了~~");
    }

    /*
        结合defaultFallback属性使用，参数列表为空，返回值和目标方法一致
        如果fallback和blockHandler都没有设置，这个设置方法生效
        如果fallback和blockHandler设置了，这个设置无效
     */
    public Result dfb(){
        return Result.error("default fallback 降级了~~");
    }

    @GetMapping("/{id}")
    @SentinelResource(value = "findById",fallback = "findById_fb",blockHandler = "findById_bh",defaultFallback = "dfb")
    public Result findById(@PathVariable("id") Integer id){
        if (id == 1){
            throw  new RuntimeException("报错了");
        }
        User user = new User();
        user.setId(id);
        user.setUsername("zhangsan-"+desc +":"+  + id);
        //订单（通过订单服务，查询用户的订单）

        //因为远程order-provider服务关闭了，这个地方远程调用会失败，会执行Feign的降级
        Result orderResult = orderFeignClient.findByUid(id);
        if (orderResult != null && orderResult.isFlag()){
            user.setOrders((List<Order>) orderResult.getData());
        }else {
            return orderResult;
        }
        return Result.success("查询成功",user);
    }

    @Autowired
    private UserService userService;

    @GetMapping("/test1")
    @SentinelResource("test1")
    public Result test1() throws InterruptedException {

        Thread.sleep(1000);

        userService.show();
        return Result.success("test1成功","success");
    }

    @GetMapping("/test2")
    @SentinelResource(value = "test2")
    public Result test2(){
        int i = 1/0;
        userService.show();
        return Result.success("test2成功","success");
    }

}
